#include "head.h"
#include "ocr.h"
#include <sys/stat.h>
#include <sys/types.h>
#include "log/writelog.h"
#include <stdlib.h>
#include <string.h>
#include<unistd.h>
#include "threadpool/thread.h"
#include "threadpool/thread_pool.h"
#include "threadpool/command.h"

#include <errno.h>
#include <signal.h>
using namespace std;
#define BUFFER_LEN 10000


int ServerPort = 20000;
int ServerType = 0;//0 测试 1 线上
//static pthread_mutex_t jsonlock;
//static pthread_mutex_t opencvlock;

struct KeyInfo
{
	char fileKey[100];
	char fileType[10];
};

struct ThreadParm
{
	int connfd;
	vector<KeyInfo>keys;
};


int JudgeBlank(char *filePath,char* fileType)
{
	return judgeBlank(filePath,fileType);	
}

int JudgeFile(KeyInfo info,vector<int> &result,int fd,int i)
{
	int start = time(NULL);	
	char localPath[200]="./image/";
	sprintf(localPath,"./image/%s_%d_%d.jpg",info.fileKey,fd,i);	
	char urlPath[500] ={0};
	if(ServerType != 0)	
		strcpy(urlPath,"http://img.willclass.com/api/show/image?fileKey=");
	else
		strcpy(urlPath,"http://img.huitong.com/api/show/image?fileKey=");

	strcat(urlPath,info.fileKey);
	int res =  CHttpClient::GetInstance()->DownloadFile(urlPath,localPath,300);
	write_log("log: downloadfile=%s d_res=%d\n",urlPath,res);
	int judge_res = -3;
	try
	{
		//Scoped lock(opencvlock);
		judge_res = JudgeBlank(localPath,info.fileType);
	}
	catch(exception &e)
	{
		write_log("JudgeFile catch exception! %s\n",e.what());
	}
	int end = time(NULL);
	result.push_back(judge_res);
	int rm_res = remove(localPath);
	write_log("log: file=%s time used=%d s judge_res=%d localPath %s rm_res %d\n",
		info.fileKey,end-start,judge_res,localPath,rm_res);
		
	return judge_res;	
}

/*void DownloadFileOnly(KeyInfo info,int fd,int i)
{
	//char urlPath[500] = "http://img.willclass.com/api/show/image?fileKey="+info.fileKey;
	char urlPath[500] = "http://img.huitong.com/api/show/image?fileKey=";
	strcat(urlPath,info.fileKey);
	char localPath[200]="./image/";
	sprintf(localPath,"./image/%s_%d_%d.jpg",info.fileKey,fd,i);
	int res =  CHttpClient::GetInstance()->DownloadFile(urlPath,localPath,300);
	write_log("log: downloadfile=%s d_res=%d\n",urlPath,res);
	return;	
}*/

bool SplitJson(char* json,vector<KeyInfo> &keys)
{
//	Scoped lock(jsonlock);
	Json::Value values;
	Json::Reader reader;
	if (reader.parse(json, values))
	{
		int count = values["count"].asInt();
		Json::Value infos = values["data"];
		if (infos.isArray())
		{
			int size = infos.size();
			Json::Value value;
			for (int i = 0; i < (int)size; i++)
			{
				KeyInfo ki;
				strcpy(ki.fileKey,infos[i]["fileKey"].asString().c_str());
				strcpy(ki.fileType, infos[i]["fileType"].asString().c_str());
				
				keys.push_back(ki);	
			}
		}
		if(count == (int)keys.size()) 
		{
			return true;
		}
	}
	return false;
}

bool Convert2Json(char *json,const vector<int> &res,const vector<KeyInfo> &keys,int code = 0)
{
//	Scoped lock(jsonlock);	
	
	Json::FastWriter fs;
	Json::Value value;
	value["count"] = res.size();
	value["code"] = code;
	for(int i = 0; i < (int)res.size(); i++)
	{
		value["data"][i]["judgeBlankImage"] = res[i];
		value["data"][i]["fileKey"] = keys[i].fileKey;
		value["data"][i]["fileType"] = keys[i].fileType;
	}
	strcpy(json,fs.write(value).c_str());
	return true;
}


bool send_response(int fd,char* response)
{
	unsigned int pos = 0;
	unsigned int len = strlen(response);
    do 
    {
        int ret = send(fd, response+pos, len-pos, 0);
		//发生错误
		if (ret <= 0)
        {
			write_log("error: send to client err ret = %d pos=%d errno=%d",ret,pos,errno);
			return false;
		}
        pos += ret;
    } while (pos < len);          
	return true;
}
	

void DoOcrJob(vector<KeyInfo> &keys,int connfd)
{
	vector<int>res;
	for(int i = 0; i < (int)keys.size(); i++)
	{
	//	write_log("log: connfd %d JudgeFile %s size %d\n",connfd,keys[i].fileKey,keys.size());
		JudgeFile(keys[i],res,connfd,i);
	}
	char json[BUFFER_LEN]={0};
	Convert2Json(json,res,keys);
	if(!send_response(connfd,json))
	{
		write_log("error: connfd %d send to client err %s",connfd,json);
	}else 
		write_log("log: connfd %d send to client  %s",connfd,json);
}

void SendError(int connfd)
{
	char json[BUFFER_LEN]={0};
	vector<int>res;
	vector<KeyInfo>keys;
	Convert2Json(json,res,keys,-1);
	if(!send_response(connfd,json))
	{
		write_log("error: connfd %d send to client err %s",connfd,json);
	}else 
		write_log("log: connfd %d send to client  %s",connfd,json);
}

bool RecvAndDownload(vector<KeyInfo> &keys,int connfd)
{	
	try
	{
		char buffer[BUFFER_SIZE+1];
		char recv_buffer[BUFFER_LEN]={0};
		int data_len= 0;
		while(true)
		{
			bzero(buffer,BUFFER_SIZE+1);
			data_len = recv(connfd,buffer,BUFFER_SIZE,0);
			if(data_len == 0) break;
			if(data_len<0)
			{
				write_log("error: 接收错误\n");
				return false;
			}
			strcat(recv_buffer,buffer);
		}
		write_log("connfd %d %s\n",connfd,recv_buffer);
		if(SplitJson(recv_buffer,keys) == false)
		{
			write_log("error: connfd %d json 解析失败\n",connfd);
			return false;
		}
		/*vector<int>res;
		for(int i = 0; i < (int)keys.size(); i++)
		{
			DownloadFileOnly(keys[i],connfd,i);
		}*/
	}
	catch(exception &e)
	{
		write_log("catch exception! %s\n",e.what());
		return false;
	}
	return true;
}

void *client_fun(int connfd)
{
	write_log("log: client_fun fd %d\n",connfd);	
	try
	{
		try
		{
			int start = time(NULL);	
			vector<KeyInfo>keys;	

			if(!RecvAndDownload(keys,connfd)) 
			{
				SendError(connfd);
				close(connfd);
				return NULL;
			}
			DoOcrJob(keys,connfd);
			int end = time(NULL);
			write_log("log: connfd=%d closed success time used = %d s  keys=%d\n",connfd,end-start,keys.size());
			close(connfd);	//关闭已连接套接字
		}
		catch(exception &e)
		{
			write_log("catch exception! %s\n",e.what());
			SendError(connfd);
			close(connfd);  //关闭已连接套接字
		}
	}
	catch(exception &e)
	{
		write_log("catch exception fun! %s\n",e.what());
	}
	return NULL;
}

void InitDir()
{
	char dir[]="./image";
    if (access(dir, 0) == -1)  
	{
		mkdir(dir, 0777);  
	}
}


int main(int argc,char **argv)
{
	if(argc < 3) 
	{
		printf("error: 参数个数错误 %d ，1:port  2: servertype\n",argc);	
		exit(1);
	}
	ServerPort = atoi(argv[1]);		
	ServerType = atoi(argv[2]);

//	pthread_mutex_init(&jsonlock, NULL);
//	pthread_mutex_init(&opencvlock, NULL);
	
	InitDir();
	log_file();	
	ThreadPool thread_pool;
	thread_pool.InitializeThreads();

	struct sockaddr_in server_addr;
	bzero(&server_addr,sizeof(server_addr));//全部置零
	//设置地址相关的属性
	server_addr.sin_family=AF_INET;
	server_addr.sin_addr.s_addr=htons(INADDR_ANY);
	server_addr.sin_port=htons(ServerPort);


	//创建套接字
	int server_socket=socket(AF_INET,SOCK_STREAM,0);
	if(server_socket<0) 
	{
		write_log("error: socket create error\n");
		exit(1);
	}
	//绑定端口
	if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
	{
		write_log("error: bind error\n");
		exit(1);
	}
	//服务器端监听
	if(listen(server_socket,LISTEN_QUEUE))
	{
		write_log("error: Server listen error\n");
		exit(1);
	}

	write_log("log: iserver run successfully\n");
	//服务器端一直运行
	int connfd = 0;
	signal(SIGPIPE, SIG_IGN);

	while(1)
	{
		try
		{
			struct sockaddr_in client_addr;
			socklen_t length=sizeof(client_addr);
			//accept返回一个新的套接字与客户端进行通信
			connfd=accept(server_socket,(struct sockaddr*)&client_addr,&length);
			
			if(connfd==-1)
			{
				write_log("error: accept error\n");
				sleep(5);
				continue;
			}
			else
			{
				write_log("log: 客户端%s连接成功connfd=%d\n",inet_ntoa(client_addr.sin_addr),connfd);
				Command command;
				command.set_cmd(0);		
				command.set_fd(connfd);
				thread_pool.AddWork(command);
			}
		}
		catch(exception &e)
		{
			write_log("catch exception main! %s\n",e.what());
		}		
	}
	close_file();
	thread_pool.ThreadDestroy();
	return 0;
}
